package com.org.oracle.strategy.impl;

import com.aliyun.oss.OSS;
import com.org.oracle.enums.ResponseCodeEnum;
import com.org.oracle.exception.CustomException;
import com.org.oracle.helper.ImageHelper;
import com.org.oracle.properties.AliyunOSSProperties;
import com.org.oracle.strategy.FileStrategy;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * @author: heiye
 * @date: 2024/11/21 下午1:33
 * @version: v1.0.0
 * @description: TODO
 */
@Slf4j
public class AliyunOSSFileStrategy implements FileStrategy {

    @Resource
    private AliyunOSSProperties aliyunOSSProperties;

    @Resource
    private OSS ossClient;

    @Resource
    private ImageHelper imageHelper;

    @Resource(name = "ossExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    /**
     * 图片上传
     *
     * @param image
     * @param bucketName
     * @return
     */
    @Override
    @SneakyThrows
    public String uploadImg(MultipartFile image, String bucketName) {
        log.info("## 图片上传至阿里云 OSS ...");

        // 判断文件是否为空
        if (image == null || image.getSize() == 0) {
            log.error("==> 上传图片异常：文件大小为空 ...");
            throw new CustomException(ResponseCodeEnum.FILE_SIZE_EMPTY);
        }

        // 文件的原始名称
        String originalFileName = image.getOriginalFilename();

        // 获取文件的后缀，如 .jpg
        String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));

        if (!".jpg".equals(suffix) && !".jpeg".equals(suffix)) {
            throw new CustomException(ResponseCodeEnum.IMAGE_TYPE_ERROR);
        }

        // 生成存储对象的名称（将 UUID 字符串中的 - 替换成空字符串）
        String key = UUID.randomUUID().toString().replace("-", "");

        // 上传图片进程
        CompletableFuture<String> originalResultFuture = CompletableFuture
                .supplyAsync(() -> {
                    // 拼接上文件后缀，即为要存储的文件名
                    String objectName = String.format("%s%s", key, suffix);
                    return uploadImgReq(image, bucketName, objectName);
                }, threadPoolTaskExecutor);
        // 上传压缩图片进程
        CompletableFuture<String> compressResultFuture = CompletableFuture
                .supplyAsync(() -> {
                    // 尽可能压缩图片到 1 MB 以下
                    MultipartFile compressedImage = imageHelper.compressImage(image);

                    // 图片不用被压缩返回空值
                    if (Objects.isNull(compressedImage)) {
                        return null;
                    }

                    // 拼接上文件后缀，即为要存储的文件名
                    String objectName = String.format("%s-compressed%s", key, suffix);
                    return uploadImgReq(compressedImage, bucketName, objectName);
                }, threadPoolTaskExecutor);

        // 异步调用
        CompletableFuture<String> resultFuture = CompletableFuture
                .allOf(originalResultFuture, compressResultFuture)
                .thenApply(s -> {
                    // 获取异步结果
                    String originalUrl = originalResultFuture.join();
                    String compressUrl = compressResultFuture.join();

                    // 压缩图片链接不为空返回
                    if (StringUtils.isNotBlank(compressUrl)) {
                        return compressUrl;
                    }
                    return originalUrl;
                });
        return resultFuture.get();
    }

    @SneakyThrows
    private String uploadImgReq(MultipartFile image, String bucketName, String objectName) {
        log.info("==> 开始上传图片至阿里云 OSS, ObjectName: {}", objectName);

        // 上传文件到阿里云 OSS
        ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(image.getInputStream().readAllBytes()));

        // 返回文件的访问链接
        String url = String.format("https://%s.%s/%s", bucketName, aliyunOSSProperties.getEndpoint(), objectName);

        log.info("==> 上传文件至阿里云 OSS 成功，访问路径: {}", url);

        return url;
    }
}
